#include "Midi.h"

void* MidiIn::midiIn = NULL;

#ifdef __WXMAC__
static void	MyReadProc(const MIDIPacketList *pktlist, void *refCon, void *connRefCon) {
	
	MIDIPacket *packet = (MIDIPacket *)pktlist->packet;
	for (unsigned int j = 0; j < pktlist->numPackets; ++j) {
		printf("RECEIVED PACKET\n");
		if(packet->length==3) {

			((MidiIn*)MidiIn::midiIn)->midiReceived(packet->data[1], packet->data[2]);
			
		}
		packet = MIDIPacketNext(packet);
	}
	/*MIDIPacket *packet = (MIDIPacket *)pktlist->packet;	// remove const (!)
	for (unsigned int j = 0; j < pktlist->numPackets; ++j) {
		for (int i = 0; i < packet->length; ++i) {
							printf("%02X ", packet->data[i]);
			
			// rechannelize status bytes
			//if (packet->data[i] >= 0x80 && packet->data[i] < 0xF0)
			//	packet->data[i] = (packet->data[i] & 0xF0) | gChannel;
		}
		
		//			printf("\n");
		packet = MIDIPacketNext(packet);
	}*/
}
#endif

#ifdef __WXMSW__
static void CALLBACK winMidiInputCallback( HMIDIOUT hmin,
                                        UINT inputStatus, 
                                        DWORD instancePtr,
                                        DWORD midiMessage,
                                        DWORD timestamp )
{
	printf("M");
	printf("i");
	printf("d");
	printf("i");
	printf(" ");
	printf("m");
	printf("e");
	printf("s");
	printf("s");
	printf("a");
	printf("g");
	printf("e");
	printf(" ");
	printf("r");
	printf("e");
	printf("c");
	printf("e");
	printf("i");
	printf("v");
	printf("e");
	printf("d");
	printf("\n");
/*
  if ( inputStatus != MIM_DATA && inputStatus != MIM_LONGDATA ) return;

  //RtMidiIn::RtMidiInData *data = static_cast<RtMidiIn::RtMidiInData *> (instancePtr);
  RtMidiIn::RtMidiInData *data = (RtMidiIn::RtMidiInData *)instancePtr;
  WinMidiData *apiData = static_cast<WinMidiData *> (data->apiData);

  // Calculate time stamp.
  apiData->message.timeStamp = 0.0;
  if ( data->firstMessage == true ) data->firstMessage = false;
  else apiData->message.timeStamp = (double) ( timestamp - apiData->lastTime ) * 0.001;
  apiData->lastTime = timestamp;

  if ( inputStatus == MIM_DATA ) { // Channel or system message

    // Make sure the first byte is a status byte.
    unsigned char status = (unsigned char) (midiMessage & 0x000000FF);
    if ( !(status & 0x80) ) return;

    // Determine the number of bytes in the MIDI message.
    unsigned short nBytes = 1;
    if ( status < 0xC0 ) nBytes = 3;
    else if ( status < 0xE0 ) nBytes = 2;
    else if ( status < 0xF0 ) nBytes = 3;
    else if ( status < 0xF3 ) {
      // A MIDI time code message and we're ignoring it.
      if ( status == 0xF1 && (data->ignoreFlags & 0x02) ) return;
      nBytes = 3;
    }
    else if ( status == 0xF3 ) nBytes = 2;
    else if ( status == 0xF8 && (data->ignoreFlags & 0x02) ) {
      // A MIDI timing tick message and we're ignoring it.
      return;
    }
    else if ( status == 0xFE && (data->ignoreFlags & 0x04) ) {
      // A MIDI active sensing message and we're ignoring it.
      return;
    }

    // Copy bytes to our MIDI message.
    unsigned char *ptr = (unsigned char *) &midiMessage;
    for ( int i=0; i<nBytes; i++ ) apiData->message.bytes.push_back( *ptr++ );
  }
  else { // Sysex message ( MIM_LONGDATA )
    MIDIHDR *sysex = ( MIDIHDR *) midiMessage; 
    if ( !( data->ignoreFlags & 0x01 ) ) {  
      // Sysex message and we're not ignoring it
      for ( int i=0; i<(int)sysex->dwBytesRecorded; i++ )
        apiData->message.bytes.push_back( sysex->lpData[i] );
    }

    // The WinMM API requires that the sysex buffer be requeued after
    // input of each sysex message.  Even if we are ignoring sysex
    // messages, we still need to requeue the buffer in case the user
    // decides to not ignore sysex messages in the future.  However,
    // it seems that WinMM calls this function with an empty sysex
    // buffer when an application closes and in this case, we should
    // avoid requeueing it, else the computer suddenly reboots after
    // one or two minutes.
    if ( apiData->sysexBuffer->dwBytesRecorded > 0 ) {
      //if ( sysex->dwBytesRecorded > 0 ) {
      MMRESULT result = midiInAddBuffer( apiData->inHandle, apiData->sysexBuffer, sizeof(MIDIHDR) );
      if ( result != MMSYSERR_NOERROR )
        std::cerr << "\nRtMidiIn::midiInputCallback: error sending sysex to Midi device!!\n\n";

      if ( data->ignoreFlags & 0x01 ) return;
    }
    else return;
  }

  if ( data->usingCallback ) {
    RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
    callback( apiData->message.timeStamp, &apiData->message.bytes, data->userData );
  }
  else {
    // As long as we haven't reached our queue size limit, push the message.
    if ( data->queueLimit > data->queue.size() )
      data->queue.push( apiData->message );
    else
      std::cerr << "\nRtMidiIn: message queue limit reached!!\n\n";
  }

  // Clear the vector for the next input message.
  apiData->message.bytes.clear();
  */
}

#endif



MidiIn::MidiIn() {
#ifdef __WXMAC__
	midiIn = this;
	MIDIClientCreate(CFSTR("MIDI Echo"), NULL, NULL, &client);
	MIDIInputPortCreate(client, CFSTR("Input port"), MyReadProc, NULL, &inPort);
	// open connections from all sources
	int n = MIDIGetNumberOfSources();
	printf("%d sources\n", n);
	for (int i = 0; i < n; ++i) {
		MIDIEndpointRef src = MIDIGetSource(i);
		MIDIPortConnectSource(inPort, src, NULL);
	}
#endif
#ifdef __WXMSW__
	int devs = midiInGetNumDevs();

	MMRESULT result = midiInOpen( &device,
                                devs-1,
                                (DWORD)&winMidiInputCallback,
                                (DWORD)NULL,
                                CALLBACK_FUNCTION );
                                
#endif
}



